package com.apes.scm.stock.transfer.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.logger.ApesLoggerService;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.jpa.spec.model.Filter;
import com.apes.framework.jpa.spec.model.Group;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.event.Listener;
import com.apes.framework.plugin.mq.MQUtil;
import com.apes.framework.plugin.outbox.OutboxPayloadWrapper;
import com.apes.framework.plugin.outbox.OutboxSubscriberService;
import com.apes.framework.plugin.outbox.annotation.OutboxSubscriber;
import com.apes.framework.plugin.soe.metadata.SceneInstance;
import com.apes.framework.util.DateUtil;
import com.apes.framework.util.MapUtil;
import com.apes.framework.util.Tools;
import com.apes.pi.service.PiManager;
import com.apes.scm.account.account.model.Stock;
import com.apes.scm.account.account.repository.StockRepository;
import com.apes.scm.account.account.service.ProductAccountService;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import com.apes.scm.masterdata.stock.model.Location;
import com.apes.scm.pur.purchaseOrder.model.PurchaseOrder;
import com.apes.scm.pur.purchaseOrder.repository.PurchaseOrderRepository;
import com.apes.scm.rbac.model.User;
import com.apes.scm.rbac.repository.UserRepository;
import com.apes.scm.stock.transfer.model.Pick;
import com.apes.scm.stock.transfer.model.PickItem;
import com.apes.scm.stock.transfer.repository.PickRepository;
import com.apestech.framework.util.StringUtil;
import com.google.common.util.concurrent.AtomicDouble;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.groupingBy;

/**
 * 功能：拣配服务
 *
 * @author xul
 * @create 2018-01-30 18:02
 */
@Service("pickService")
public class PickService extends DomainService {

    @Autowired
    PickRepository pickRepository;

    @Autowired
    ProductAccountService productAccountService;

    @Autowired
    private OutboxSubscriberService outboxSubscriberService;

    @Autowired
    private PiManager piManager;

    /**
     * 功能：创建拣配单
     *
     * @param request
     * @return
     */
    @Listener(topic = "event:stock.pick.create")
    public Pick create(SimpleRequest request) {
        Pick pick = save(request);

        // 自动交货收货方式无需生成运单 (异步)
        if (StringUtils.isEmpty(pick.isAuto())) pick.setAuto(false);
        if(!pick.isAuto()) MQUtil.publish("tms.waybill.setWaybill","交货单自动生成运单", MapUtil.mapped(pick));
        return pick;
    }

    @Listener(topic = "event:stock.pick.save")
    public Pick save(SimpleRequest request) {
        Pick pick = request.getO(Pick.class);

        if (StringUtils.isEmpty(pick.getCreator()) ){
            // 找系统
            pick.setUserId("0");
        } else {
            User user = SpringManager.getBean(UserRepository.class).findAll(JpaDsl.toCriteriaByEq("person.id", pick.getCreator())).stream().findFirst().orElse(null);
            if (Objects.isNull(user)) { // 操作人不是员工，可能是供应商，没有 User
                pick.setUserId("0");
            } else {
                pick.setUserId(user.getId() + "");
            }

        }

        return savePick(pick);

    }

    private Pick savePick(Pick pick) {
        pick.setCompany(pick.getLocation().getCompany());
        if (Tools.isNull(pick.getState())) {
            pick.setState("confirmed");
        }
        pick.setDateOrder(new Date());
        return pickRepository.saveAndFlush(pick);
    }

    /**
     * 生成多个交货单
     * @param request 传入的值为 List<Pick>
     * @return 返回传入的 List<Pick>
     */
    public List<Pick> createPickList(SimpleRequest request){
        List<Pick> list = request.getA(Pick.class);
        list.forEach( pick -> {
            //第一步：创建交货单
            Pick newPick = savePick(pick);
            //第二步：写日志
            writeLog("0",newPick.getInnerBusinessType(),newPick.getId());
        });
        return list;
    }


    /**
     * 交货
     */
    @Listener(topic = "event:stock.pick.pda")
    public Pick delivery(SimpleRequest request) {
        Pick fromPick = request.getO(Pick.class);
        Pick pick = pickRepository.findOne(fromPick.getId());
        if (pick == null) throw new RuntimeException("拣配单：" + fromPick.getId() + " 在系统中不存在！");
        if (pick.getVersion() != fromPick.getVersion()) throw new RuntimeException("记录已更新或已删除，请重新提交！");
        if (pick.getState().equals("done")) throw new RuntimeException("拣配单：" + fromPick.getId() + " 在系统中已完成交货！");
        if (pick.getState().equals("cancel")) throw new RuntimeException("拣配单：" + fromPick.getId() + " 在系统中已取消！");
        //判断第三方交货是否有收货凭证
        if (Objects.nonNull(fromPick.getSignVoucher()))pick.setSignVoucher(fromPick.getSignVoucher());
        /** 交货处理 **/
        AtomicDouble countDoneQty = new AtomicDouble(0);
        Map<Long, List<PickItem>> pickItems = pick.getPickItems().stream().collect(groupingBy(PickItem::getId));
        fromPick.getPickItems().forEach((fromPickItem) -> {
            List<PickItem> items = pickItems.get(fromPickItem.getId());
            if (items == null || items.isEmpty()) {
                throw new RuntimeException("拣配单行号：" + fromPickItem.getId() + " 输入错误！");
            }
            countDoneQty.set(countDoneQty.get() + fromPickItem.getQtyDone());
            items.stream().forEach((pickItem -> pickItem.delivery(fromPickItem.getQtyDone())));
        });
        if (countDoneQty.get() == 0) throw new RuntimeException("无交货数量！");
        Location location = pick.getLocation();

        // 自动交接货无需生成运单
        if(!pick.isAuto())sendSynEvent("event:tms.waybill.setWaybillCargoDetails", pick);
        //如果是分销单来源的 交货单，需检查保管数是否足够，因为分销单可以超卖
        if (Objects.equals("SaleOrder",pick.getOriginBusinessType())){
            pick.getPickItems().forEach(
                    item -> {
                        Stock stock = SpringManager.getBean(StockRepository.class).findByProductAndLocation(item.getProduct(), location);
                        if (stock.getCustodyQty() < item.getQtyDone()) {
                            throw new RuntimeException("该商品库存不足，编码：" +item.getProduct().getId());
                        }
                    });
        }
        /** 帐务处理 **/
        Processingccount(pick);

        /** 延期交货 **/
        backorder(pick);

        /** 删除交货数量为零的记录明细 **/
        deleteDoneByZero(pick);

        if (request.getPerson() != null && pick.getDoneUid() == null) pick.setDoneUid(((PartyRole) request.getPerson()));
        if (StringUtils.isEmpty(pick.getCreator())) pick.setCreator("system");
        if (pick.getDoneUid() == null) pick.setDoneUid(SpringManager.getBean(PartyRoleRepository.class).findOne(pick.getCreator()));
        if (StringUtil.isEmpty(pick.getUserId()) && pick.getDoneUid() != null) {
            User user = SpringManager.getBean(UserRepository.class).findAll(JpaDsl.toCriteriaByEq("person.id", pick.getDoneUid().getId())).stream().findFirst().get();
            pick.setUserId(user.getId() + "");
        }
        pick.delivery();
        pick.setUpdateDate(new Date());
        pick = pickRepository.saveAndFlush(pick);


        /** 发送交货消息 **/
        sendDeliveryMessage(pick);
//        invoke("fn.servicePlan.writeBackServicePlan",MapUtil.mapped(pick));  // 回写方案明细到货数量
        this.sendBaturuReceipt(pick.getSupplierPartyB(), pick.getParcelListNo(), pick.getLocation(), pick.getOrigin());
        return pick;
    }

    private void sendBaturuReceipt(String supplierPartyB, String parcelListNo, Location location, String origin) {
        PurchaseOrder order = SpringManager.getBean(PurchaseOrderRepository.class).findOne(origin);
        if (order == null || order.getSupplier().getName().indexOf("巴图鲁") == -1) return;
        List packageDTOS = new ArrayList();
        packageDTOS.add(MapUtil.mapper("packageNo", parcelListNo, "supplierId", supplierPartyB));
        invoke("stock.pickService.confirmReceipt",
                MapUtil.mapper("storeId", location.getDepot().getDept().getOrigin(), "orderNo", order.getSupplierRef(), "packageDTOS", packageDTOS));
    }

    /**
     * 帐务处理
     **/
    private void Processingccount(Pick pick) {
        pick.getPickItems().stream().filter(pickItem -> pickItem.getQtyDone() != 0)
                .forEach((pickItem) -> {
                    if (pick.getOperation().equalsIgnoreCase("receipt")) { //收货
                        //写商品库存帐可用数
                        productAccountService.setProductAvailable(pickItem.getProduct(), pick.getLocation(), pickItem.getUom(), Math.abs(pickItem.getQtyDone()), pick.getOriginBusinessType(), pick.getOrigin(), pickItem.getOriginLine(), "交货单收货", pick.getCompany());
                        //写商品库存帐保管数
                        productAccountService.setProductCustody(pickItem.getProduct(), pick.getLocation(), pickItem.getUom(), Math.abs(pickItem.getQtyDone()), pick.getOriginBusinessType(), pick.getOrigin(), pickItem.getOriginLine(), "交货单收货", pick.getCompany());
                    } else if (pick.getOperation().equalsIgnoreCase("deliver")) { //发货
                        //写商品库存帐保管数
                        productAccountService.setProductCustody(pickItem.getProduct(), pick.getLocation(), pickItem.getUom(), -1 * Math.abs(pickItem.getQtyDone()), pick.getOriginBusinessType(), pick.getOrigin(), pickItem.getOriginLine(), "交货单发货", pick.getCompany());
                    }
                });
    }

    /**
     * 删除交货数量为零的记录明细
     **/
    private void deleteDoneByZero(Pick pick) {
        Iterator<PickItem> it = pick.getPickItems().iterator();
        while (it.hasNext()) {
            PickItem pickItem = it.next();
            if (pickItem.getQtyDone() == 0) {
                it.remove();
            }
        }
    }

    /**
     * 功能：发送交货消息
     */
    public void sendDeliveryMessage(Pick pick) {
        if (StringUtils.isEmpty(pick.getOrigin())) return;
        Map result = deliveryMapping(pick);
        outboxSubscriberService.commonSendRequest("local:stock.pick.delivery", pick.getId(), new JSONObject(result));

        //通知第三方收货
        outboxSubscriberService.commonSendRequest("local:stock.pick.thirdParty", pick.getId(), new JSONObject(MapUtil.mapper("pick", pick.getId())));
    }

    @OutboxSubscriber(id = "local:stock.pick.delivery", name = "发送交货消息")
    private void sendDeliveryMessage(OutboxPayloadWrapper outboxPayloadWrapper) {
        sendSynEvent("event:stock.pick.delivery", outboxPayloadWrapper.getPayload());
    }

    /**
     * 通知第三方收货
     * @param outboxPayloadWrapper
     */
    @OutboxSubscriber(id = "local:stock.pick.thirdParty", name = "发送交货消息")
    private void thirdParty(OutboxPayloadWrapper outboxPayloadWrapper){
        JSONObject jsonObject = JSON.parseObject(outboxPayloadWrapper.getPayload());
        Pick pick = pickRepository.findOne(jsonObject.getString("pick"));
        sendSynEvent("event:stock.pick.thirdParty", MapUtil.mapped(pick));
    }


    private Map deliveryMapping(Pick pick) {
        Set<Map> items = pick.getPickItems().stream()
                .filter(pickItem -> pickItem.getQtyDone() != 0)
                .map(pickItem -> {
                    Map item = new HashMap();
                    item.put("pickItemId", pickItem.getId());
                    item.put("originItemId", pickItem.getOriginLine());
                    item.put("productId", pickItem.getProduct().getId());
                    item.put("qtyDone", pickItem.getQtyDone());
                    return item;
                }).collect(Collectors.toSet());
        Map result = new HashMap();
        result.put("originBusinessType", pick.getOriginBusinessType());
        result.put("origin", pick.getOrigin());
        result.put("pickId", pick.getId());
        result.put("operation", pick.getOperation());
        result.put("dateDone", DateUtil.format(pick.getDateDone(), DateUtil.SHOW_DATETIME_MILLI_FORMAT));
        result.put("items", items);
        result.put("auto",pick.isAuto());
        return result;
    }

    /*
     * 延期交货
     */
    public void backorder(Pick pick) {
        Set<PickItem> pickItems = pick.getPickItems().stream()
                .filter(pickItem -> pickItem.getProductUomQty() != pickItem.getQtyDone())
                .map(pickItem -> {
                    PickItem toItem = new PickItem();
                    toItem.setProduct(pickItem.getProduct());
                    toItem.setUom(pickItem.getUom());
                    toItem.setOrderedQty(pickItem.getOrderedQty());
                    toItem.setFrostQty(pickItem.getFrostQty());
                    pickItem.setFrostQty(0.0);
                    toItem.setProductUomQty(pickItem.getProductUomQty() - pickItem.getQtyDone());
                    toItem.setOriginLine(pickItem.getOriginLine());
                    return toItem;
                }).collect(Collectors.toSet());
        if (pickItems.size() == 0) return;
        Pick backorder = new Pick();
        backorder.setPickItems(pickItems);
        backorder.setBackorder(pick);
        backorder.setCompany(pick.getCompany());
        backorder.setPartner(pick.getPartner());
        backorder.setLocation(pick.getLocation());
        backorder.setReceiptLocation(pick.getReceiptLocation());
        backorder.setMoveType(pick.getMoveType());
        backorder.setOrigin(pick.getOrigin());
        backorder.setOperation(pick.getOperation());
        backorder.setOriginBusinessType(pick.getOriginBusinessType());
        backorder.setScene(pick.getScene());
        backorder.setCreator(pick.getCreator());
        backorder.setCustomerExpandId(pick.getCustomerExpandId());
        if (StringUtils.isEmpty(pick.getCreator()) ){
            // 找系统
            pick.setUserId("0");
        }else {
            User user = SpringManager.getBean(UserRepository.class).findAll(JpaDsl.toCriteriaByEq("person.id", pick.getCreator())).stream().findFirst().get();
            backorder.setUserId(user.getId() + "");
        }
        savePick(backorder);
        this.writeLog(backorder.getUserId(), backorder.getInnerBusinessType(), backorder.getInnerBusinessKey());
        SceneInstance sceneInstance = pick.sceneInstance();
        backorder.createSceneRole(sceneInstance);
    }

    /**
     * 冻结、解冻
     */
    public Pick frost(SimpleRequest request) {
        Map data = request.getMap();
        Pick pick = pickRepository.findOne(JpaDsl.toCriteriaByEq("state", "confirmed", "origin", data.get("id"), "originBusinessType", data.get("innerBusinessType"))).orElse(null);
        if (pick == null) throw new RuntimeException("订单：" + data.get("id") + " 没有有效的交货单！");
        for (Map item : ((List<Map>) data.get("items"))) {
            PickItem pickItem = pick.getPickItems().stream().filter(pi -> pi.getOriginLine().equals(item.get("id"))).findFirst().orElse(null);
            if (pickItem == null) throw new RuntimeException("订单明细：" + item.get("id") + " 没有有效的交货明细！");
            pickItem.frost(((Number) item.get("frostQty")).doubleValue());
        }
        return pickRepository.saveAndFlush(pick);
    }

    /**
     * 取消
     */
    public Pick cancel(SimpleRequest request) {
        Map data = request.getMap();
        Map conditions = new HashMap();
        conditions.put("state", "confirmed");
        conditions.put("origin", data.get("id"));
        conditions.put("originBusinessType", data.get("innerBusinessType"));
        if (data.containsKey("operation") && StringUtils.hasText(data.get("operation").toString())) {
            conditions.put("operation", data.get("operation"));
        }
        Pick pick = pickRepository.findOne(JpaDsl.toCriteria(conditions)).orElse(null);
        if (pick == null) throw new RuntimeException("订单：" + data.get("origin") + " 没有有效的交货单！");
        for (Map item : ((List<Map>) data.get("items"))) {
            PickItem pickItem = pick.getPickItems().stream().filter(pi -> pi.getOriginLine().equals(item.get("id"))).findFirst().orElse(null);
            if (pickItem == null) throw new RuntimeException("订单明细：" + item.get("id") + " 没有有效的交货明细！");
            pickItem.cancle(((Number) item.get("cancelQty")).doubleValue());
        }

        /** 延期交货 **/
        backorder(pick);

        /** 删除取消数量为零的记录明细 **/
        deleteDoneByZero(pick);

        if (request.getPerson() == null && data.get("cancelUid") != null) {
            pick.setDoneUid(SpringManager.getBean(PartyRoleRepository.class).findOne(data.get("cancelUid").toString()));
        } else {
            pick.setDoneUid(request.getPerson());
        }
        pick.cancel();
        pick = pickRepository.saveAndFlush(pick);

        /** 发送取消消息 **/
        sendCancelMessage(pick);
        /** 终止运单 **/
        invoke("tms.waybill.repeal", MapUtil.mapper("sourceBusinessKey", pick.getId(),"sourceBusinessType",pick.getInnerBusinessType()));
        return pick;
    }

    /**
     * 功能：发送取消消息
     */
    public void sendCancelMessage(Pick pick) {
        if (StringUtils.isEmpty(pick.getOrigin())) return;
        Map result = deliveryMapping(pick);
        sendSynEvent("event:stock.pick.cancel", result);
    }

    /**
     * 功能：提供流程编排中获取交货单数据
     *
     * @param request
     * @return
     */
    public Map<String, Object> returnPick(SimpleRequest request) {
        Pick pick = request.getO(Pick.class);
        Map<String, Object> returnMap = deliveryMapping(pick);
        return returnMap;
    }

    /***
     * 自动交接货(用于场景流)
     */
    public Pick autoDeliverOrReceipt(SimpleRequest request) {
        Pick pick = request.getO(Pick.class);

        // 设置交货数量
        pick.getPickItems().forEach(pickItem -> pickItem.setQtyDone(pickItem.getProductUomQty()));

        if (StringUtils.isEmpty(pick.getCreator())) pick.setCreator("system");
        if (pick.getDoneUid() == null) pick.setDoneUid(SpringManager.getBean(PartyRoleRepository.class).findOne(pick.getCreator()));
        return  (Pick) this.sendSynEvent("event:stock.pick.pda", pick).get(0);

    }

    // 撤回
    public Pick withdraw(SimpleRequest request) {
        Pick pick = request.getO(Pick.class);
        if (pick.getWithDrawButtonHide()) throw new RuntimeException("单据状态已变更，请刷新界面！");
//        pick.setState("withdraw");
        pick.setWithdrawUid(request.getPerson());
        pick.setWithdrawData(new Date());

        // 只有生成收货方的交货单才能撤回
        List existsReceiptsPick = pickRepository.findAll("SELECT ID FROM STOCK_PICK WHERE ORIGIN = '"+ pick.getOrigin() +"' AND STATE = 'confirmed' AND OPERATION = 'receipt'");
        if (existsReceiptsPick.size() == 0) throw new RuntimeException("请检查是否生成收货方的交货单，请生成后再撤回！");

        // 写入撤回日志
//        this.writeLog(pick.getWithdrawUid().getId(), pick.getInnerBusinessType(), pick.getId());

        if (StringUtil.isEmpty(pick.getUserId())) {
            User user = SpringManager.getBean(UserRepository.class).findAll(JpaDsl.toCriteriaByEq("person.id", pick.getWithdrawUid().getId())).stream().findFirst().get();
            pick.setUserId(user.getId() + "");
        }

        // 先撤回
        pick = pickRepository.save(pick);

        // 后生成新的交货单
        outboxSubscriberService.commonSendRequest("local:stock.pick.withdrawHandleThirdPartyDocuments", pick.getId(), new JSONObject(withDrawMapping(pick)));

        Map result = deliveryMapping(pick);
        result.put("operator", "withdraw");
        sendSynEvent("event:stock.pick.withdraw", result);
        return pick;

    }

    // 撤回 - 写日志
    private void writeLog(String personId, String innerBusinessType, String innerBusinessKey) {
        SpringManager.getBean(ApesLoggerService.class).sendSynEvent("event:ir.logger.create", MapUtil.mapper(
                "businessType", innerBusinessType,
                "businessKey", innerBusinessKey,
                "operate", "创建交货单", "operator_id", personId
        ));
    }

    // 撤回 - 传给第三方数据包装
    private Map withDrawMapping(Pick pick) {
        List<Map> pickMaps = pick.getPickItems().stream().map(pickItem -> {
            return MapUtil.mapper("originItemId", pickItem.getOriginLine(), "qtyDone", pickItem.getQtyDone(), "productId", pickItem.getProduct().getId());
        }).collect(Collectors.toList());
        return MapUtil.mapper("pickId", pick.getId(), "origin", pick.getOrigin(), "originBusinessType", pick.getOriginBusinessType(),  "cancelUid", pick.getWithdrawUid().getId(), "item", pickMaps);
    }

    @OutboxSubscriber(id = "local:stock.pick.withdrawHandleThirdPartyDocuments", name = "交货撤回写第三方单据")
    public void withdrawHandleThirdPartyDocuments(OutboxPayloadWrapper outboxPayloadWrapper) {
        if (outboxPayloadWrapper.getPayload().indexOf("\"originBusinessType\":\"CrossCompanyTransferNew\"") > 0) {
            invoke("cross.company.transferNew.pickWithdraw", outboxPayloadWrapper.getPayload());
        } else {
            invoke("stock.transfer.pickWithdraw", outboxPayloadWrapper.getPayload());
        }
    }


    /***
     * 关联采购单号 上游单号 第三方单号 原始单号进行查询
     * 一般情景不建议使用
     */
    public Page<Pick> findAllRelate(SimpleRequest request) {
        Group group = findAllCore(request);
        return pickRepository.findAll(group.build(true), JpaDsl.getPageable(request));
    }

    public List<Pick> findAllRelateNoPage(SimpleRequest request) {
        Group group = findAllCore(request);
        return pickRepository.findAll(group.build(true));
    }

    public Page<Pick> findAllRelatePrint(SimpleRequest request) {
        Group group = findAllCore(request);
        String printState = group.getFilters().stream().filter(filter -> filter.getField().equals("printState")).map(filter -> filter.getValue().toString()).collect(Collectors.toList()).get(0);
        group.setFilters(group.getFilters().stream().filter(filter -> !filter.getField().equals("printState")).collect(Collectors.toList()));

        // 对应车牌转换为赋能扩展表编码
        this.carLisenceCovertFnCustomerId(group.getFilters());
        List<Pick> all = pickRepository.findAll(group.build(true));
        convertData(all);
        if ("1".equals(printState)) {
            List<Pick> notPrint = all.stream().filter(e -> e.getPrintNumber() == 0).collect(Collectors.toList());
            return autoPage(request,notPrint);
        } else if("2".equals(printState)) {
            List<Pick> Print = all.stream().filter(e -> e.getPrintNumber() > 0).collect(Collectors.toList());
            return autoPage(request,Print);
        }

        return autoPage(request,all);
    }

    // 对应车牌转换为赋能扩展表编码
    private void carLisenceCovertFnCustomerId(List<Filter> filters) {
        filters.stream()
                .filter(f -> f.getField().equals("customerExpandId"))
                .forEach(f -> {
                    f.setOperator("IN");
                    List<Pick> p = pickRepository.findAll(this.findFnCustomerIdSql(f.getValue().toString()));
                    if (p.isEmpty()) {
                        f.setValue("");
                    } else {
                        f.setValue(pickRepository.findAll(this.findFnCustomerIdSql(f.getValue().toString())));
                    }
                });

    }

    // 获取赋能扩展表 id sql
    private String findFnCustomerIdSql(String carLicense) {
        return "SELECT DISTINCT B.ID " +
                "  FROM STOCK_PICK A, FN_CUSTOMER_EXPAND B " +
                " WHERE A.CUSTOMER_EXPAND_ID = B.ID " +
                "   AND B.CAR_LICENSE = '"+ carLicense + "'";
    }

    /***
     * 默认传入权限
     */
    public Pick findOneRelate(SimpleRequest request) {
        List<Pick> picks = findAllRelateNoPage(request);
        if (picks.size() > 1) throw new RuntimeException("通过当前的查询条件找到多条对应的交货单，请确认，对应的交货单订单号为：" +
                picks.stream().map(purchaseOrder -> purchaseOrder.getId()).reduce("", (d1, d2) -> {
                    if (d1 == null || d1.equals("")) return d2;
                    return d1 + ";" + d2;
                }, String::concat));
        return picks.stream().findFirst().orElse(null);
    }


    /***
     * 抽取的公共逻辑
     */
    private Group findAllCore(SimpleRequest request) {
        Group group = JpaDsl.getGroup(request);

        List<Filter> filters = group.getFilters();

        // 筛选出对应的id， 用于匹配 第三方单号 原始单号 上游单号
        Filter filter = filters.stream().filter( item -> item.getField().equals("id")).findFirst().orElse(null);

        if( filter != null ) {
            filters.remove(filter); // 移除当前选项
            group.addGroup(createIdGroup(filter));
        }
        return group;
    }


    /***
     * 构建订单 Group
     */
    private Group createIdGroup(Filter filter) {
        Group idGroup = new Group();
        idGroup.setOperator("or");

        // 采购订单
        Group purchaseGroup = createPurchaseGroup(filter);
        if (purchaseGroup.getFilters().size() != 0) {
            idGroup.addGroup(purchaseGroup);
        }

        idGroup.addGroup(createNormalGroup(filter)); // 普通订单
        return idGroup;
    }



    /***
     * 构建采购订单的 group
     */
    private Group createPurchaseGroup(Filter filter) {
        // 查询对应的采购订单是否存在
        List idFilter = new ArrayList();
        idFilter.add(MapUtil.mapper("field", "id", "operator", "EQ", "value", filter.getValue(), "externalDocument", "EQ", "value", filter.getValue()));
        Map m = MapUtil.mapper("condition", idFilter);
        List<PurchaseOrder> purchaseOrders = invoke("purchase.order.findAllRelateNoPage", m);

        Group idGroup = new Group();
        if (purchaseOrders != null && purchaseOrders.size() != 0) {
            // 查询采购订单
            idGroup.setOperator("and");
            idGroup.addFilters(JpaDsl.toFilter(
                    "origin", "IN", purchaseOrders.stream().map(purchaseOrder -> purchaseOrder.getId()).toArray(String[]::new),
                    "originBusinessType", "EQ", "PurchaseOrder"
            ));
        }
        return idGroup;
    }


    /***
     * 构建普通订单 group
     */
    private Group createNormalGroup(Filter filter) {
        Group idGroup = new Group();

        idGroup.setOperator("or");
        idGroup.addFilters(JpaDsl.toFilter(
                "id", "EQ", filter.getValue(),
                "origin", "EQ", filter.getValue()
        ));
        return idGroup;
    }

    public JSONObject queryYHDTrack(SimpleRequest simpleRequest) {
        List<Map> findIdRequireLogisticss = invoke("stock.requireLogisticsService.findIdRequireLogistics", simpleRequest.getJO().getJSONObject("node"));
        JSONObject returnData = new JSONObject();
        JSONArray itemArray = new JSONArray();
        JSONObject item = new JSONObject();
        item.put("ITEM", findIdRequireLogisticss);
        itemArray.add(item);
        returnData.put("CDATA", itemArray);
        return returnData;
    }

    public List<Pick> convertData(List<Pick> all) {
        all.forEach(e->{
            double num = invoke("print.record.findOne", mapper("id", e.getId()));
            e.setPrintNumber(num);
        });
        return all;
    }

    public Page autoPage(SimpleRequest request, List<Pick> data) {
        List<Pick> pageResult;
        int page = Integer.valueOf(request.get("page").toString());
        int size = Integer.valueOf(request.get("size").toString());
        if (data.size() < page*size) return null;
        if (data.size() <= size*(page +1)) {
            pageResult  = data.subList(page*size,data.size());
        }else {
            pageResult  = data.subList(page*size,size*(page +1));
        }
        Pageable pageable = PageRequest.of(request.get("page"), request.get("size"));
        PageImpl pageImpl = new PageImpl<>(pageResult, pageable, data.size());
        return pageImpl;
    }

    public Page getOriginBusinessType(SimpleRequest request) {
        List<Map> type = pickRepository.getPickType();
        type = type.stream().map(map -> {
            Map result = new HashMap<>();
            result.put("id",map.get("ID"));
            result.put("name",map.get("NAME"));
            return result;
        }).collect(Collectors.toList());
        return new PageImpl<>(type, PageRequest.of(request.get("page"), request.get("size")), type.size());
    }

    // 批量取消 - 已知单号全部商品都需要取消
    public Pick batchCancel(SimpleRequest request) {
        HashMap conditions = (HashMap) request.getMap();
        conditions.put("state", "confirmed");

        HashMap copyCondi = (HashMap) conditions.clone();
        copyCondi.remove("cancelUid");
        Pick pick = pickRepository.findOne(JpaDsl.toCriteria(copyCondi)).orElse(null);
        if (pick == null) throw new RuntimeException("订单：" + request.get("origin") + " 没有有效的交货单！");
        pick.getPickItems().forEach(pickItem -> { // 赋值已完成数量
            pickItem.setQtyDone(pickItem.getProductUomQty() > 0?pickItem.getProductUomQty():pickItem.getOrderedQty());
        });

        // 延期交货
        backorder(pick);

        // 删除取消数量为零的记录明细
        deleteDoneByZero(pick);

        if (request.get("cancelUid") != null) {
            pick.setDoneUid(SpringManager.getBean(PartyRoleRepository.class).findOne(request.get("cancelUid").toString()));
            pick.setWithdrawUid(SpringManager.getBean(PartyRoleRepository.class).findOne(request.get("cancelUid").toString()));
        } else {
            pick.setDoneUid(request.getPerson());
            pick.setWithdrawUid(request.getPerson());
        }

        if (StringUtil.isEmpty(pick.getUserId())) {
            User user = SpringManager.getBean(UserRepository.class).findAll(JpaDsl.toCriteriaByEq("person.id", pick.getWithdrawUid().getId())).stream().findFirst().get();
            pick.setUserId(user.getId() + "");
        }

        pick.setWithdrawData(new Date());
        pick.cancel();
        pick = pickRepository.saveAndFlush(pick);

        /** 发送取消消息 **/
        sendCancelMessage(pick);

        /** 终止运单 **/
        invoke("tms.waybill.repeal", MapUtil.mapper("sourceBusinessKey", pick.getId(),"sourceBusinessType",pick.getInnerBusinessType()));
        return pick;
    }

    // 调拨取消专用
    public void dumpCancel(SimpleRequest request) {
        Map data = request.getMap();
        Map conditions = new HashMap();
        conditions.put("state", "confirmed");
        conditions.put("origin", data.get("id"));
        conditions.put("originBusinessType", data.get("innerBusinessType"));
        if (data.containsKey("operation") && StringUtils.hasText(data.get("operation").toString())) {
            conditions.put("operation", data.get("operation"));
        }
        List<Pick> picks = pickRepository.findAll(JpaDsl.toCriteria(conditions));
        if (picks.isEmpty()) throw new RuntimeException("订单：" + data.get("origin") + " 没有有效的交货单！");
        picks.forEach(pick -> {
            for (Map item : ((List<Map>) data.get("items"))) {
                // 交货为一次性交货
                PickItem pickItem = pick.getPickItems().stream().filter(pi -> pi.getOriginLine().equals(item.get("id"))).findFirst().orElse(null);

                if (pickItem == null) throw new RuntimeException("订单明细：" + item.get("id") + " 没有有效的交货明细！");
                double cancelQty = ((Number) item.get("cancelQty")).doubleValue();
                double newQtyDone = cancelQty > pickItem.getProductUomQty() - pickItem.getFrostQty()?pickItem.getProductUomQty() - pickItem.getFrostQty():cancelQty;
                pickItem.setQtyDone(newQtyDone);
            }

            /** 延期交货 **/
            backorder(pick);

            /** 删除取消数量为零的记录明细 **/
            deleteDoneByZero(pick);

            if (request.getPerson() == null && data.get("cancelUid") != null) {
                pick.setDoneUid(SpringManager.getBean(PartyRoleRepository.class).findOne(data.get("cancelUid").toString()));
            } else {
                pick.setDoneUid(request.getPerson());
            }
            pick.cancel();
            pick = pickRepository.saveAndFlush(pick);

            /** 发送取消消息 **/
            sendCancelMessage(pick);
            /** 终止运单 **/
            invoke("tms.waybill.repeal", MapUtil.mapper("sourceBusinessKey", pick.getId(),"sourceBusinessType",pick.getInnerBusinessType()));
        });
    }

    private Object searchChangeCondition(SimpleRequest request){
        JSONObject jo = request.getJO();
        JSONArray condition = jo.getJSONArray("condition");
        JSONArray newCondition = new JSONArray();
        for (Object o : condition) {
            if (!(o instanceof JSONObject)){
                newCondition.add(o);
                continue;
            }
            JSONObject jsonObject = (JSONObject) o;
            switch (jsonObject.getString("field")) {
                case "terminal":
                    break;
                default:
                    newCondition.add(jsonObject);
            }
        }
        jo.put("condition",newCondition);
        return jo;
    }
}
